﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SOEN341_SCHEDULER_PHASE1
{
    class TableGridPublicStaticMethods
    {
        const int LOWEST_VALUE_HOUR = 8;
        const int MAX_VALUE_HOUR = 22;
        const int LOWEST_VALUE_MINUTE = 0;
        const int MAX_VALUE_MINUTE = 60;
        const int INTERVAL_VALUE_MINUTE = 15;
        const int BLOCKS_PER_HOUR = MAX_VALUE_MINUTE / INTERVAL_VALUE_MINUTE;

        public TableLayoutPanel defaultTableGrid;
        public Font defaultSelectedFont;
        

        public bool addingConstraints = false;
        public ToolStripStatusLabel ui_st_toDisplay;
        private Label startTimeSelected = null;
        private Label daySelected = null;
        private Label endTimeSeleccted = null;
        private bool startSelected = false;

        Label[] ui_lbl_grid_day = new Label[5];
        Label[] ui_lbl_grid_time = new Label[57];

        private List<Label> addedLabels;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public TableGridPublicStaticMethods()
        {

        }

        /// <summary>
        /// Initialize the Font and Labels (Time/Day)
        /// </summary>
        /// <param name="selectedFont">Font for default labels</param>
        public void TableGridInitializeGenerateDefaultLabels(Font selectedFont)
        {
            addedLabels = new List<Label>();

            //time column label

            Label ui_lbl_grid_time_column = new Label();
            ui_lbl_grid_time_column.Text = "Time";
            Object[] nullTag = new Object[2];
            ui_lbl_grid_time_column.Tag = nullTag;
            ui_lbl_grid_time_column.TextAlign = ContentAlignment.TopLeft;
            ui_lbl_grid_time_column.Font = selectedFont;
            defaultTableGrid.Controls.Add(ui_lbl_grid_time_column, 0, 0);
            defaultSelectedFont = selectedFont;
            Object[] toTag = new Object[2];
            toTag[1] = null;
            //day labels
            for (int i = 0; i < ui_lbl_grid_day.Length; i++)
            {
                toTag = new Object[2];
                ui_lbl_grid_day[i] = new Label();
                ui_lbl_grid_day[i].TextAlign = ContentAlignment.MiddleCenter;
                ui_lbl_grid_day[i].Font = selectedFont;
                ui_lbl_grid_day[i].DoubleClick += new EventHandler(ui_lbl_DayCaptions_DoubleClick);
                toTag[0] = i;
                ui_lbl_grid_day[i].Tag = toTag;
            }

            ui_lbl_grid_day[0].Text = "Monday";
            ui_lbl_grid_day[1].Text = "Tuesday";
            ui_lbl_grid_day[2].Text = "Wednesday";
            ui_lbl_grid_day[3].Text = "Thursday";
            ui_lbl_grid_day[4].Text = "Friday";

            for (int i = 0; i < ui_lbl_grid_day.Length; i++)
            {
                defaultTableGrid.Controls.Add(ui_lbl_grid_day[i], i + 1, 0);
            }


            //for the interval calculations
            int currentTimeMinutes = 0;
            int currentTimeHours = LOWEST_VALUE_HOUR;
            CustomDateTime cdtTag;
            for (int i = 0; i < ui_lbl_grid_time.Length; i++)
            {
                toTag = new Object[2];
                ui_lbl_grid_time[i] = new Label();

                ui_lbl_grid_time[i].DoubleClick += new EventHandler(ui_lbl_TimeCaptions_DoubleClick);

                //smaller font
                ui_lbl_grid_time[i].Font = selectedFont;

                //go by 15 min interval
                if (currentTimeMinutes < 10)
                {
                    ui_lbl_grid_time[i].Text = currentTimeHours + ":0" + currentTimeMinutes;
                }
                else
                {
                    ui_lbl_grid_time[i].Text = currentTimeHours + ":" + currentTimeMinutes;
                }

                cdtTag = new CustomDateTime(currentTimeHours, currentTimeMinutes, 0, 0, null);
                toTag[0] = cdtTag;
                currentTimeMinutes += INTERVAL_VALUE_MINUTE;
                if (currentTimeMinutes == MAX_VALUE_MINUTE)
                {
                    currentTimeMinutes = LOWEST_VALUE_MINUTE;
                    currentTimeHours++;
                }
                ui_lbl_grid_time[i].Tag = toTag;
                defaultTableGrid.Controls.Add(ui_lbl_grid_time[i], 0, i + 1);
            }
        }

        void ui_lbl_TimeCaptions_DoubleClick(object sender, EventArgs e)
        {
            Label theLabel = (Label)sender;

            if (addingConstraints)
            {
                if (!startSelected)
                {
                    for (int i = 0; i < ui_lbl_grid_time.Length; i++)
                    {
                        ui_lbl_grid_time[i].ForeColor = Color.Black;
                    }
                }

                if (!startSelected)
                {
                    theLabel.ForeColor = Color.Green;
                    startTimeSelected = theLabel;
                }
                else
                {
                    //make sure its not less than small
                    if (theLabel.Top <= startTimeSelected.Top)
                    {
                        ui_st_toDisplay.Text = "Invalid end time!";
                        ui_st_toDisplay.ForeColor = Color.Red;
                    }
                    else
                    {
                        theLabel.ForeColor = Color.Green;
                        endTimeSeleccted = theLabel;
                    }
                }

                if (daySelected==null)
                {
                    ui_st_toDisplay.Text = "Select a day!";
                    ui_st_toDisplay.ForeColor = Color.Green;
                }

                VerifyNewConstraint();
            }
        }

        void ui_lbl_DayCaptions_DoubleClick(object sender, EventArgs e)
        {
            Label theLabel = (Label)sender;

            if (addingConstraints && !startSelected)
            {
                for (int i = 0; i < ui_lbl_grid_day.Length; i++)
                {
                    ui_lbl_grid_day[i].ForeColor = Color.Black;
                }

                theLabel.ForeColor = Color.Green;

                daySelected = theLabel;
                if (startTimeSelected==null)
                {
                    ui_st_toDisplay.Text = "Select a time!";
                    ui_st_toDisplay.ForeColor = Color.Green;
                }

                VerifyNewConstraint();
            }
        }

        public void ResetConstraintsUI()
        {
            daySelected = null;
            startSelected = false;
            startTimeSelected = null;
            endTimeSeleccted = null;

            for (int i = 0; i < ui_lbl_grid_day.Length; i++)
            {
                ui_lbl_grid_day[i].ForeColor = Color.Black;
            }

            for (int i = 0; i < ui_lbl_grid_time.Length;i++)
            {
                ui_lbl_grid_time[i].ForeColor = Color.Black;
            }
        }

        void VerifyNewConstraint()
        {
            if (daySelected != null && startTimeSelected != null && !startSelected)
            {
                ui_st_toDisplay.Text = "Select end time!";
                ui_st_toDisplay.ForeColor = Color.Green;
                startSelected = true;
                daySelected.ForeColor = Color.Blue;
                startTimeSelected.ForeColor = Color.Blue;
            }
            if (startSelected && endTimeSeleccted != null)
            {
                addingConstraints = false;
                //check constraint
                Object[] theTags;
                theTags = (Object[])startTimeSelected.Tag;
                CustomDateTime cdtStart = (CustomDateTime)theTags[0];
                theTags = (Object[])endTimeSeleccted.Tag;
                CustomDateTime cdtEnd = (CustomDateTime)theTags[0];              

                theTags = (Object[])daySelected.Tag;
                int col = (int)theTags[0];

                DayOfWeek dt = GetDayOfWeek(col);
                List<DayOfWeek> theDayOfWeek = new List<DayOfWeek>();
                theDayOfWeek.Add(dt);

                CustomDateTime finalCdt = new CustomDateTime(cdtStart.GetStartHour(), cdtStart.GetStartMinute(),
                    cdtEnd.GetStartHour(), cdtEnd.GetStartMinute(), theDayOfWeek);

                TimeTableBlock theTtb= new TimeTableBlock(finalCdt, "CONSTRAINT", Color.Black);
                if (CheckCollision(theTtb,col))
                {
                    ui_st_toDisplay.Text = "Collision detected - Select new date/time";
                    ui_st_toDisplay.ForeColor = Color.Red;
                    ResetConstraintsUI();
                    addingConstraints = true;
                    ResetConstraintsUI();
                }
                else
                {
                    addingConstraints = true;
                    AddGridBlock(theTtb);
                    ui_st_toDisplay.Text = "Constraint Added - Repeat process to add a new one";
                    ui_st_toDisplay.ForeColor = Color.Green;
                    GlobalVariablesClass.session_loggedInStudent.GetConstraints().AddConstraint(finalCdt);
                    ResetConstraintsUI();
                }
            }
        }

        DayOfWeek GetDayOfWeek(int col)
        {
            switch (col)
            {
                case 0:
                    return DayOfWeek.Monday;
                case 1:
                    return DayOfWeek.Tuesday;
                case 2:
                    return DayOfWeek.Wednesday;
                case 3:
                    return DayOfWeek.Thursday;
                case 4:
                    return DayOfWeek.Friday;
            }
            return DayOfWeek.Monday;
        }


        public bool CheckCollision(CustomDateTime cdt, int col)
        {
            int startRow = GetRowNumber(cdt, true);
            int endRow = GetRowNumber(cdt, false);
            int rowSpan = endRow - startRow;
            return CheckCollision(startRow, rowSpan, col);
        }

        /// <summary>
        /// Check collision @ row,column @ a span
        /// </summary>
        /// <param name="startRow">Row to check</param>
        /// <param name="span">Row span</param>
        /// <param name="column">Column</param>
        /// <returns>TRUE: COLLISION, FALSE: NO COLLISION</returns>
        public bool CheckCollision(int startRow, int span, int column)
        {
            Control ctlTest;

            for (int i = startRow; i <= startRow + span; i++)
            {
                ctlTest = defaultTableGrid.GetControlFromPosition(column, i);
                if (ctlTest != null)
                {
                    return true;
                }
            }

            return false;
        }
        public bool CheckCollision(TimeTableBlock ttb, int col)
        {
            CustomDateTime cdt = ttb.GetCustomDateTime();
            int startRowNumber = GetRowNumber(cdt, true);
            startRowNumber--;
            int endRowNumber = GetRowNumber(cdt, false);
            endRowNumber--;
            endRowNumber--;
            int rowSpan = endRowNumber - startRowNumber;
            startRowNumber++;
            col++;
            return CheckCollision(startRowNumber,rowSpan,col);

        }
        /// <summary>
        /// Check Collision of a course
        /// </summary>
        /// <param name="cs">Course to check</param>
        /// <returns>TRUE: COLLIDED FALSE: NO COLLISION</returns>
        public bool CheckCollision(Course cs)
        {
            if (cs == null)
                return false;
            TimeTableBlock ttb = cs.GetTimeTableBlock();
            CustomDateTime cdt = ttb.GetCustomDateTime();
            int startRowNumber = GetRowNumber(cdt, true);
            startRowNumber--;
            int endRowNumber = GetRowNumber(cdt, false);
            endRowNumber++;
            int rowSpan = endRowNumber - startRowNumber;
            DayOfWeek[] arrDay = cdt.GetDayOfWeek().ToArray();
            for (int i = 0; i < arrDay.Length; i++)
            {
                if (CheckCollision(startRowNumber, rowSpan - 1, (int)arrDay[0]))
                {
                    return true;
                }
            }
            return false;
            
        }

        /// <summary>
        /// Add a block to the grid 
        /// </summary>
        /// <param name="ui_tableLayout">The table to add block to</param>
        /// <param name="selectedFont">Font needed</param>
        /// <param name="ttb">TimeTableBlock to add to grid</param>
        public bool AddGridBlock(TimeTableBlock ttb)
        {
            if (defaultTableGrid != null)
            {
                CustomDateTime cdt = ttb.GetCustomDateTime();
                string courseName = ttb.GetSubject();
                string courseRoom = ttb.GetLocation();

                int startRowNumber = GetRowNumber(cdt, true);
                int endRowNumber = GetRowNumber(cdt, false);
                int rowSpan = endRowNumber - startRowNumber;
                List<DayOfWeek> daysOfWeek = cdt.GetDayOfWeek();
                DayOfWeek[] arrDayOfWeek = daysOfWeek.ToArray();
                //int dayOfWeek=(int)custDateTime.GetDayOfWeek();

                //MessageBox.Show(startRowNumber.ToString() + " || " + endRowNumber.ToString());
                Label[] ui_lbl_toAdd = new Label[arrDayOfWeek.Length];

                bool isCollide;
                Object[] toTag = new Object[2];
                for (int i = 0; i < arrDayOfWeek.Length; i++)
                {
                    ui_lbl_toAdd[i] = new Label();
                    toTag[1] = ttb;
                    ui_lbl_toAdd[i].Tag = toTag;
                    ui_lbl_toAdd[i].AutoSize = true;
                    ui_lbl_toAdd[i].BackColor = ttb.GetBlocColor();
                    ui_lbl_toAdd[i].Dock = DockStyle.Fill;
                    ui_lbl_toAdd[i].Font = defaultSelectedFont;
                    ui_lbl_toAdd[i].TextAlign = ContentAlignment.MiddleCenter;
                    ui_lbl_toAdd[i].Text = courseName + " " + "\n" + courseRoom + "\n" +
                        cdt.GetTimeInterval();

                    int dayOfThis = (int)arrDayOfWeek[i];

                    addedLabels.Add(ui_lbl_toAdd[i]);

                    if (addingConstraints)
                    {
                        ui_lbl_toAdd[i].DoubleClick += new EventHandler(ui_label_Constraint_DoubleClick_handler);
                        ui_lbl_toAdd[i].ForeColor = Color.White;
                        ui_lbl_toAdd[i].BackColor = Color.Black;
                        ui_lbl_toAdd[i].Text = ttb.GetCustomDateTime().GetTimeInterval();
                    }

                    isCollide = CheckCollision(startRowNumber, rowSpan - 1, dayOfThis);

                    if (!isCollide)
                    {
                        defaultTableGrid.Controls.Add(ui_lbl_toAdd[i], dayOfThis, startRowNumber);
                        defaultTableGrid.SetRowSpan(ui_lbl_toAdd[i], rowSpan);
                    }
                    else
                    {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }

        void ui_label_Constraint_DoubleClick_handler(object sender, EventArgs e)
        {
            Label theLabel= (Label) sender;
            TimeTableBlock ttb = (TimeTableBlock)((Object[])theLabel.Tag)[1];
            CustomDateTime cdt = ttb.GetCustomDateTime();
            Constraint cnt = GlobalVariablesClass.session_loggedInStudent.GetConstraints();
            //this is a constraint
            DialogResult dr = MessageBox.Show("Do you want to remove this constraint [" +
                ttb.GetCustomDateTime().GetTimeInterval() + "]?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dr == DialogResult.Yes)
            {
                cnt.RemoveConstraint(cdt);
                Clear();
                GenerateStudentSchedule(GlobalVariablesClass.courseSelected);
                addingConstraints = true;
                DisplayStudentConstraints(GlobalVariablesClass.session_loggedInStudent);
                addingConstraints = false;
                ui_form_StudentPage.changeMade = true;
            }
        }

        /// <summary>
        /// Refresh the TTB colors on the grid
        /// </summary>
        public void RefreshTtbGridColors()
        {
            TimeTableBlock ttb;
            foreach (Control ctl in defaultTableGrid.Controls)
            {
                Label theLabel = ctl as Label;
                if (theLabel != null)
                {
                    //get ttb
                    ttb = (TimeTableBlock)((Object[])theLabel.Tag)[1];
                    if (ttb != null)
                    {
                        theLabel.BackColor = ttb.GetBlocColor();
                    }
                }
            }
        }

        /// <summary>
        /// Clear all on grid
        /// </summary>
        public void Clear()
        {
            Label[] arrLab = addedLabels.ToArray();

            for (int i = 0; i < arrLab.Length; i++)
            {
                defaultTableGrid.Controls.Remove(arrLab[i]);
            }
        }

        /// <summary>
        /// Add a course to grid
        /// </summary>
        /// <param name="cs">Course to add</param>
        /// <returns>TRUE: added FALSE: Collision detected</returns>
        public bool AddCourseToGrid(Course cs)
        {
            //get course ttb
            TimeTableBlock ttb = cs.GetTimeTableBlock();
            return AddGridBlock(ttb);
        }

        public bool GenerateStudentSchedule(List<Course> toDisplay)
        {
            Course[] arrCoursesToDisplay = toDisplay.ToArray();

            Course theTutorial;
            Course theLab;

            if (arrCoursesToDisplay.Length > 0)
            {
                for (int i = 0; i < arrCoursesToDisplay.Length; i++)
                {
                    theTutorial = arrCoursesToDisplay[i].GetTutorial();
                    theLab = arrCoursesToDisplay[i].GetLab();
                    if (theTutorial != null)
                    {
                        AddCourseToGrid(theTutorial);
                    }
                    if (theLab != null)
                    {
                        AddCourseToGrid(theLab);
                    }
                    AddCourseToGrid(arrCoursesToDisplay[i]);
                }

                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Generates a student schedule on the grid provided
        /// </summary>
        /// <param name="std">Student to generate schedule from</param>
        /// <param name="ui_tableLayout">grid to display info on</param>
        public bool GenerateStudentSchedule(Student std)
        {
            List<Course> listOfCourses = std.GetCurrentCourses();
            Course[] arrCoursesToDisplay = listOfCourses.ToArray();

            Course theTutorial;
            Course theLab;

            if (arrCoursesToDisplay.Length > 0)
            {
                for (int i = 0; i < arrCoursesToDisplay.Length; i++)
                {
                    theTutorial = arrCoursesToDisplay[i].GetTutorial();
                    theLab = arrCoursesToDisplay[i].GetLab();
                    if (theTutorial != null)
                    {
                        AddCourseToGrid(theTutorial);
                    }
                    if (theLab != null)
                    {
                        AddCourseToGrid(theLab);
                    }
                    AddCourseToGrid(arrCoursesToDisplay[i]);
                }

                return true;
            }
            else
            {
                return false;
            }
        }

        public void DisplayStudentConstraints(Student std)
        {
            addingConstraints = true;
            List<CustomDateTime> theConstraints = std.GetConstraints().GetConstraints();
            CustomDateTime[] arrCdt = theConstraints.ToArray();
            TimeTableBlock toGenerate;
            for (int i = 0; i < arrCdt.Length; i++)
            {
                toGenerate = new TimeTableBlock(arrCdt[i], "CONSTRAINT", Color.Black);
                AddGridBlock(toGenerate);
            }
            addingConstraints = false;
        }

        /// <summary>
        /// Change font of the grid
        /// </summary>
        /// <param name="toChange">Font to change</param>
        public void ChangeFont(Font toChange)
        {
            
            foreach (Control ctl in defaultTableGrid.Controls)
            {
                Label theLabel = ctl as Label;
                if (theLabel != null)
                {
                    theLabel.Font =toChange;
                }
            }
        }
        

        /// <summary>
        /// returns row number
        /// </summary>
        /// <param name="cdt">custome date time</param>
        /// <param name="getStart">TRUE: return start time row # 
        /// FALSE: return end time row #</param>
        /// <returns></returns>
        public int GetRowNumber(CustomDateTime cdt, bool getStart)
        {
            int hour;
            int minute;
            int row;

            //constraints

            if (getStart)
            {
                //get hour first
                hour = cdt.GetStartHour();
                minute = cdt.GetStartMinute();
            }
            else
            {
                hour = cdt.GetEndHour();
                minute = cdt.GetEndMinute();
            }

            //set hour to be at the FIRST block of that hour time
            row = hour - LOWEST_VALUE_HOUR;
            row *= BLOCKS_PER_HOUR;
            row++;

            //for minute
            row += minute / INTERVAL_VALUE_MINUTE;
            return row;
        }




    }
}
